#include <databaselib/io/ODBC.h>
#include <utillib/memory/memory.h>
#include <stdio.h>
#include <databaselib/io/DBCommon.h>

using namespace databaselib::io;


ODBC::ODBC( AgentODBC *parentDB )	: m_parentAgentDB ( parentDB )
{

	initialize();
}

ODBC::~ODBC()
{
	release();
}

bool ODBC::connect()
{
	if ( isConnect() ) return ( true );

	SQLRETURN result;

	result = SQLAllocEnv( &m_env );
	if ( !sqlOK( result ) ) return false;

	result = SQLAllocConnect( m_env, &m_dbc);
	if (!sqlOK(result)) return false;

	result = SQLDriverConnect (m_dbc, NULL, (BYTE *)m_parentAgentDB->getDBConnString(), SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);

	if (!sqlOK(result)) return false;

	result = SQLAllocStmt( m_dbc,&m_stmt );
	return ( sqlOK ( result ) );
}

void ODBC::initialize( void )
{
	m_env = SQL_NULL_HANDLE;
	m_dbc = SQL_NULL_HANDLE;
	m_stmt = SQL_NULL_HANDLE;
	m_isFetch = false;
}

bool ODBC::prepare( const char * query )
{
	if ( !isConnect() ) return ( false );

	if ( m_isFetch == true ) endFetch();

	SQLRETURN result = SQLPrepare( m_stmt, ( BYTE *)query ,SQL_NTS );

	if ( sqlOK( result ) == true )
	{
		m_isExecute = true;
		return ( true );
	}
	release();

	return ( false );
}

bool ODBC::execute()
{
	SQLRETURN result = SQLExecute( m_stmt );
	if ( sqlOK( result ) == true ) return ( true );
	release();
	return ( false );
}

bool ODBC::executeSQL( const char * query )
{
	if ( prepare( query ) )
	{
		SQLSetStmtOption( m_stmt, SQL_CURSOR_TYPE, SQL_CURSOR_STATIC );

		if ( execute() ) return ( true );
	}
#ifdef _DEBUG
	printf( "Query Execute Error :'%s'\r\n", query );
#endif
	WriteLog::getInstance()->put( query );
	return ( false );
}

int ODBC::getColumnType( SQLUSMALLINT col )
{
	if ( m_isFetch == false ) return ( -1 );
	int type=SQL_C_DEFAULT;

	UCHAR szColName[256];
	SWORD swCol,swType,swScale,swNull;
	UDWORD pcbColDef;

	SQLDescribeCol( m_stmt,col,szColName,256, &swCol, &swType, &pcbColDef, &swScale, &swNull );

	type= ( int )swType;

	return type;
}

bool ODBC::fetch( void )
{
	if ( m_isExecute == false ) return ( false );

	SQLRETURN result = SQLFetch( m_stmt );

	m_columnNo = 0;
	if( sqlOK( result ) == true ) m_isFetch = true;
	else m_isFetch = false;

	return ( m_isFetch );
}

bool ODBC::getColumnName( SQLUSMALLINT col , char *name)
{
	if ( m_isFetch == false ) return ( false );

	UCHAR colName[256];
	SWORD swCol,swType,swScale,swNull;
	UDWORD pcbColDef;

	SQLDescribeCol( m_stmt,col,colName,256,&swCol,&swType,&pcbColDef,&swScale,&swNull );

	strcpy( ( char *)name, ( char *)colName);
	trimRight( (unsigned char *)name );

	return true;
}

int ODBC::getColumnID( char *field,char *table )
{
	if ( m_isFetch == false ) return ( -1 );
	UCHAR szColName[256];
	UCHAR szOwner[256];
	SWORD swCol,swType,swScale,swNull;
	UDWORD pcbColDef;
	SDWORD wColLen;

	SQLUSMALLINT col = 1;

	SQLColAttributes( m_stmt,0,SQL_COLUMN_COUNT,szOwner,256,&swScale,&wColLen );
	int nMaxCols=(int)wColLen;

	while ( col <= nMaxCols )
	{
		int nRet=SQLDescribeCol( m_stmt,col,szColName,256,&swCol,&swType,&pcbColDef,&swScale,&swNull );
		SQLColAttributes( m_stmt,col,SQL_COLUMN_TABLE_NAME,szOwner,256,&swScale,&wColLen );

		if( nRet != SQL_SUCCESS )
		{
			col=0;
			break;
		}

		trimRight( szColName );
		trimRight( szOwner );

		if( !strcmp( ( char *)szColName, field ) )
		{
			if(  strlen(table) > 0 )
			{
				if( !strcmp( ( char *)szOwner,table ) ) break;
				else col++;
			}
			else break;
		}
		else col++;
	}
	return col;
}


void ODBC::close( void )
{
	endFetch();
	if( m_stmt != SQL_NULL_HANDLE )
	{
		SQLFreeStmt( m_stmt, SQL_DROP );
		m_stmt = SQL_NULL_HANDLE;
	}
}

bool ODBC::release()
{
	endFetch();
	m_stmt = SQL_NULL_HANDLE;
	if (m_dbc != SQL_NULL_HANDLE)
	{
		SQLDisconnect ( m_dbc );
		SQLFreeHandle(SQL_HANDLE_DBC, m_dbc);
	}
	m_dbc = SQL_NULL_HANDLE;

	if (m_env != SQL_NULL_HANDLE)  SQLFreeHandle (SQL_HANDLE_ENV, m_env);
	m_env = SQL_NULL_HANDLE;

	return ( true );
}

bool ODBC::trimRight( unsigned char *value )
{
	if ( ( value == NULL ) || ( !strlen( (char *)value ) ) ) return ( false );

	for ( int i = ( int )strlen( ( char *)value ); i >= 0 ; i-- )
	{
		if ( *(value + i ) != ' ' ) break;
		*(value + i ) = '\0';
	}
	return ( true );
}


bool ODBC::sqlOK( SQLRETURN result )
{
	if ( ( result == SQL_SUCCESS ) || ( result == SQL_SUCCESS_WITH_INFO ) ) return ( true );
	return ( false );
}

void ODBC::endFetch()
{
	if ( isConnect() && m_isFetch )
	{
		SQLCloseCursor( m_stmt );
	}
	m_isFetch = false;
	m_isExecute = false;
}

bool ODBC::bindParameter( BYTE order, BYTE inout, BYTE cType, BYTE sqlType,  void *value, int valueLength,  DWORD columnSize, BYTE degit )
{
	SQLINTEGER param = SQL_NTS;
	SQLRETURN ret = SQLBindParameter( m_stmt, order, inout, cType, sqlType, columnSize, degit, value, valueLength, &param );

	return ( sqlOK( ret ) );
}


AgentODBC::AgentODBC() : m_port( 1433 )
{
	strcpy( m_dsnName, "(Default)" );
}
AgentODBC::~AgentODBC()
{
}

bool AgentODBC::initializeDataBaseEnv( char *dataBaseIP, char *defaultDB, char *userid, char *password )
{
	if ( ( dataBaseIP == NULL ) || ( userid == NULL ) || ( password == NULL ) ) return ( false );

	m_dbConnString = new char[ 256 ];

	wsprintf( m_dbConnString, "DSN=%s;DB=%s;SYSDB=;SERVER=%s;UID=%s;PWD=%s;PORT=%d;OPTION=16384;STMT=;", m_dsnName, defaultDB, dataBaseIP, userid, password, m_port );
	//	wsprintf( m_dbConnString, "DSN=%s;UID=%s;PWD=%s", datasource, userid, password );

	return ( true );
}

bool AgentODBC::releaseDataBaseEnv()
{
	SAFE_DELETE( m_dbConnString );
	return ( true );
}


Database * AgentODBC::getNewDBInstance()
{
	ODBC *dataBase = new ODBC( this );

	dataBase->connect();
	return ( dataBase );
}
